<?php

/**
 * @package Bike
 * @subpackage Db
 */

/**
 * Class for use mysql through mysql_ API
 * @author Chrome
 * @package Bike
 * @subpackage Db
 */
class Bike_Db_Mysql implements Bike_Db_Idb {

	/**
	 * Connection to database
	 * @var resource
	 */
	protected $connection = null;

	/**
	 * Constructor check params, establish connection to database server and send initial query to db
	 * @param string $dbHost
	 * @param string $dbName
	 * @param string $dbUser
	 * @param string $dbPass
	 * @param array $dbOptions
	 * @param string $initialQuery
	 * @throws Bike_Db_Exception
	 * @throws Bike_db_Exception
	 */
	public function __construct($dbHost, $dbName, $dbUser, $dbPass, array $dbOptions = array(), $initialQuery = '') {
		if(!extension_loaded('mysql')){
			throw new Bike_Db_Exception('The mysql extention is required for this database layer', Bike_Db_Exception::REQUIRED_EXTENSION_NOT_LOADED);
		}
		$this->connection = @mysql_connect($dbHost,$dbUser, $dbPass, true);
		if(empty($this->connection)){
			throw new Bike_Db_Exception('Can not connect to database', Bike_Db_Exception::MYSQL_CANT_CONNECT_TO_HOST);
		}
		if(!mysql_select_db($dbName, $this->connection)){
			throw new Bike_db_Exception(mysql_error($this->connection), mysql_errno($this->connection));
		}
		if(!empty($initialQuery)){
			$this->query($initialQuery);
		}
	}

	/* (non-PHPdoc)
	 * @see Bike_Db_Idb::delete()
	 */
	public function delete($prefix, $name, $id) {
		$queryStr = 'DELETE FROM `' . $prefix . $name . '` WHERE `id` = ' . (int)$id;
		try {
			$this->query($queryStr);
		}catch(Bike_Db_Exception $e){
			return false;
		}
		return true;
	}

	/* (non-PHPdoc)
	 * @see Bike_Db_Idb::fetchData()
	 */
	public function fetchData($prefix, $name, $filters, $offset, $limit, array $sortings = array()) {
		$limits = '';
		if(0 < $limit){
			$limits = ' LIMIT ' . $limit . ' OFFSET ' . $offset;
		}
		$sortings_array = array();
		if(!empty($sortings)){
			foreach($sortings as $field => $direction){
				$sortings_array[] = '`' . $field . '` ' . (strtolower($direction) == 'asc' ? 'ASC' : 'DESC');
			}
			$sortings_array[0] = ' ORDER BY ' . $sortings_array[0];
		}
		$result = array('items' => array(), 'totalCount' => 0);
		try{
			$result = array(
				'items' => $this->query('SELECT SQL_CALC_FOUND_ROWS * FROM `' . $prefix .  $name . '` ' . (!empty($filters) ? 'WHERE ' . $filters : '' ) . implode(', ', $sortings_array) . $limits),
			);
			$query_result = $this->query('SELECT FOUND_ROWS()', self::FETCH_RESULT_NUM);
			$result['totalCount'] = $query_result[0][0];
		}catch(Bike_Db_Exception $e){
			$result = array('items' => array(), 'totalCount' => 0);
		}
		return $result;
	}

	/* (non-PHPdoc)
	 * @see Bike_Db_Idb::insert()
	 */
	public function insert($prefix, $name, array $data) {
		$fields = array();
		$values = array();
		foreach($data as $key => $value){
			$fields[] = '`' . $key . '`';
			$values[] = $this->quote($value);
		}
		$queryStr = 'INSERT INTO `' . $prefix . $name . '` (' . implode(', ', $fields) . ') VALUES (' . implode(',', $values) . ')';
		try{
			$this->query($queryStr);
		}catch(Bike_Db_Exception $e){
			return false;
		}
		return true;
	}

	/* (non-PHPdoc)
	 * @see Bike_Db_Idb::makeFilters()
	 */
	public function makeFilters(array $filters) {
		$finalFilter = '';
		foreach ($filters as $filter){
			if('FIND_IN_SET' == strtoupper($filter['operation'])){
				$finalFilter .= (empty($finalFilter) ? ' ' : ' AND ') . ' FIND_IN_SET(' . $this->quote($filter['value']) . ', ' . $filter['field'] . ')';
			}else{
				$finalFilter .= (empty($finalFilter) ? ' ' : ' AND ') . ' `' . $filter['field'] . '` ' . $filter['operation'] . ' ' . $this->quote($filter['value']);
			}
		}
		return $finalFilter;
	}

	/* (non-PHPdoc)
	 * @see Bike_Db_Idb::update()
	 */
	public function update($prefix, $name, $id, array $data) {
		$preparedData = array();
		foreach($data as $key => $value){
			$preparedData[] = '`' . $key . '` = ' . $this->quote($value) . ' ';
		}
		$queryStr = 'UPDATE `' . $prefix . $name . '` SET ' . implode(',', $preparedData) . ' WHERE `id` = ' . $this->quote($id);
		try{
			$this->query($queryStr);
		}catch(Bike_Db_Exception $e){
			return false;
		}
		return true;
	}

	/* (non-PHPdoc)
	 * @see Bike_Db_Idb::query()
	 */
	public function query($query, $fetchMode = self::FETCH_RESULT_ASSOC){
		$query_result = mysql_query($query, $this->connection);
		if(is_resource($query_result)){
			$resultMode = MYSQL_ASSOC;
			switch($fetchMode){
				case self::FETCH_RESULT_NUM:
					$resultMode = MYSQL_NUM;
					break;
				case self::FETCH_RESULT_BOTH:
					$resultMode = MYSQL_BOTH;
					break;
			}
			$result = array();
			while($row = mysql_fetch_array($query_result, $resultMode)){
				$result[] = $row;
			}
			return $result;
		}
		if(FALSE === $query_result){
			throw new Bike_Db_Exception(mysql_error($this->connection), Bike_Db_Exception::QUERY_ERROR);
		}
		return $query_result;
	}

	/**
	 * Quote value for sending it to database
	 * @param string $value
	 * @return string
	 */
	protected function quote($value){
		if (get_magic_quotes_gpc()) {
			$value = stripslashes($value);
		}
		return '"' . mysql_real_escape_string($value, $this->connection) . '"';
	}

	/**
	 * Destruct object
	 */
	public function __destruct(){
		if(!empty($this->connection)){
			mysql_close($this->connection);
		}
		$this->connection = null;
	}
}
